package mebp.genetic.mutation;

import mebp.genetic.Individuum;
import mebp.genetic.Population;

import org.apache.log4j.Logger;

public class RandomDoubleMutation implements MutationStrategy {

	Logger log = Logger.getLogger(RandomDoubleMutation.class);
	private double probability;
	private Boolean keepBadMutations;
	private int mutationStrength;
	
	public void setMutationStrength(int mutationStrength) {
		this.mutationStrength = mutationStrength;
	}

	public RandomDoubleMutation(double probability, Boolean keepBadMutations) {
		this.probability = probability;
		this.keepBadMutations = keepBadMutations;
		this.mutationStrength = 1;
	}
	
	// spaltet einen graphen an *einer* beliebigen stelle und setzt ihn dann neu zusammen
	public void mutate(Population population) {
		for (Individuum i:population) {
			if (Math.random()<probability) {
				
				Individuum iold = null;
				if (!keepBadMutations) {
					iold = (Individuum)i.clone();
				}
				// Mutate this
				i.optimizeLightAndCheck();

				int elem = (int) Math.round(Math.random() * (i.genom.length - 1));
				if (i.genom[elem] >= mutationStrength+1) {
					// decrement
					i.genom[elem] = i.genom[elem] - mutationStrength;
				} else {
					// increment
					i.genom[elem] = i.genom[elem] + mutationStrength;
				}
				int elem2 = (int) (Math.random() * i.genom.length);
				while (Math.abs((elem2-elem))<2) {
					elem2 = (int) (Math.random() * i.genom.length);
				}
				if (i.genom[elem2] >= mutationStrength+1) {
					// decrement
					i.genom[elem2] = i.genom[elem2] - mutationStrength;
				} else {
					// increment
					i.genom[elem2] = i.genom[elem2] + mutationStrength;
				}
				i.invalidateCache();
				i.repair();

				if (!keepBadMutations) {
					double before=iold.getFitness();
					double after = i.getFitness();
					// float improvement =
					// (Math.round((after/before-1)*10000)/100f)*-1;
					if (after < before) {
						log.trace("Mutation improved Fitness by "
								+ (Math.round((after / before - 1) * 10000) / 100f)
								* -1 + "%");
					} else {
						i = iold;
					}
				}
			}		
		}
	}
}
